Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit c4a0116f510cd0884144800d2f5e2430434fb1e1


Parents : 2f3af2a
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-24T17:56:54-05:00

feat(conversation): integrate uuid for pending message hash and update viewport resize handling

Changes
Diff

diff --git a/meshchatx/src/frontend/components/messages/ConversationViewer.vue b/meshchatx/src/frontend/components/messages/ConversationViewer.vue
index 6713e1be..ca2f8bcc 100644
--- a/meshchatx/src/frontend/components/messages/ConversationViewer.vue
+++ b/meshchatx/src/frontend/components/messages/ConversationViewer.vue
@@ -1532,6 +1532,7 @@ import "emoji-picker-element";
import StickerView from "../stickers/StickerView.vue";
import InViewAnimatedImg from "./InViewAnimatedImg.vue";
import TelemetryHistoryModal from "./telemetry/TelemetryHistoryModal.vue";
+import { v4 as uuidv4 } from "uuid";
export default {
name: "ConversationViewer",
@@ -2087,6 +2088,11 @@ export default {
this.windowWidth = window.innerWidth;
};
window.addEventListener("resize", this._onWindowResize);
+ this._visualViewport = typeof window !== "undefined" ? window.visualViewport : null;
+ if (this._visualViewport) {
+ this._visualViewport.addEventListener("resize", this._onWindowResize);
+ this._visualViewport.addEventListener("scroll", this._onWindowResize);
+ }
},
beforeUnmount() {
this.scrollBottomGen += 1;
@@ -2096,6 +2102,12 @@ export default {
}
if (this._onWindowResize) {
window.removeEventListener("resize", this._onWindowResize);
+ if (this._visualViewport) {
+ this._visualViewport.removeEventListener("resize", this._onWindowResize);
+ this._visualViewport.removeEventListener("scroll", this._onWindowResize);
+ this._visualViewport = null;
+ }
+ this._onWindowResize = null;
}
if (this.updateTimer) {
clearInterval(this.updateTimer);
@@ -4050,7 +4062,7 @@ export default {
try {
job.pendingHash = null;
if (job.canOptimisticPending) {
- const pendingHash = `pending-${crypto.randomUUID()}`;
+ const pendingHash = `pending-${uuidv4()}`;
job.pendingHash = pendingHash;
const pendingFields = {};
if (job.images.length > 0) {

diff --git a/tests/frontend/MessageSendingFailures.test.js b/tests/frontend/MessageSendingFailures.test.js
index 5562083e..2efb3e1b 100644
--- a/tests/frontend/MessageSendingFailures.test.js
+++ b/tests/frontend/MessageSendingFailures.test.js
@@ -92,6 +92,34 @@ describe("MessageSendingFailures.test.js", () => {
expect(DialogUtils.alert).toHaveBeenCalledWith("Sending failed");
});
+ it("sends plain text when crypto.randomUUID is unavailable (non-secure context)", async () => {
+ DialogUtils.alert.mockClear();
+
+ const c = globalThis.crypto;
+ vi.stubGlobal("crypto", {
+ ...c,
+ getRandomValues: c.getRandomValues.bind(c),
+ randomUUID: undefined,
+ });
+
+ const wrapper = mountConversationViewer();
+ wrapper.vm.newMessageText = "http LAN host";
+
+ await wrapper.vm.sendMessage();
+
+ expect(DialogUtils.alert).not.toHaveBeenCalled();
+ expect(axiosMock.post).toHaveBeenCalledWith(
+ "/api/v1/lxmf-messages/send",
+ expect.objectContaining({
+ lxmf_message: expect.objectContaining({
+ content: "http LAN host",
+ destination_hash: "test-hash",
+ }),
+ })
+ );
+ expect(wrapper.vm.chatItems.some((item) => item.lxmf_message.hash === "mock")).toBe(true);
+ });
+
it("updates UI when message state becomes failed via WebSocket", async () => {
const wrapper = mountConversationViewer();
const messageHash = "msg-123";


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────